`timescale 1ns / 1ps
/******************************************************************************
*                                                                             *
* UTICA softcore v0.1                                                         *
*                                                                             *
* Copyright (c) 2012 Andrew D. Zonenberg                                      *
* All rights reserved.                                                        *
*                                                                             *
* Redistribution and use in source and binary forms, with or without modifi-  *
* cation, are permitted provided that the following conditions are met:       *
*                                                                             *
*    * Redistributions of source code must retain the above copyright notice  *
*      this list of conditions and the following disclaimer.                  *
*                                                                             *
*    * Redistributions in binary form must reproduce the above copyright      *
*      notice, this list of conditions and the following disclaimer in the    *
*      documentation and/or other materials provided with the distribution.   *
*                                                                             *
*    * Neither the name of the author nor the names of any contributors may be*
*      used to endorse or promote products derived from this software without *
*      specific prior written permission.                                     *
*                                                                             *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF        *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN     *
* NO EVENT SHALL THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT,         *
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT    *
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,   *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY       *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT         *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF    *
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.           *
*                                                                             *
******************************************************************************/

/**
	@file HexUartPrinter.v
	@author Andrew D. Zonenberg
	@brief Glue logic for printing data as hex
 */
module HexUartPrinter(
	clk,
	busy,
	uart_tx, uart_rx,
	tx_data, tx_en, space_en, newline_en
    );
	 
	////////////////////////////////////////////////////////////////////////////////////////////////
	// IO declarations
	input wire clk;
	
	output reg busy = 0;
	
	output wire uart_tx;
	input wire uart_rx;
	
	input wire[7:0] tx_data;
	input wire tx_en;
	input wire space_en;
	input wire newline_en;

	////////////////////////////////////////////////////////////////////////////////////////////////
	// The UART (no receive mode implemented)
	wire uart_tx_busy;
	reg uart_txen = 0;
	reg[7:0] uart_txdata = 0;
	UART uart (
		.clk(clk), 
		.clkdiv(16'd695), 
		.tx(uart_tx), 
		.txin(uart_txdata), 
		.txrdy(uart_txen), 
		.txactive(uart_tx_busy), 
		.rx(uart_rx)//, 
		//.rxout(rxout), 
		//.rxrdy(rxrdy), 
		//.rxactive(rxactive), 
		//.overflow(overflow)
		);
		
	////////////////////////////////////////////////////////////////////////////////////////////////
	// Transmit mode logic
	
	wire[7:0] high_char;
	wire[7:0] low_char;
	HexConverter high_converter (.din(tx_data[7:4]), .dout(high_char));
	HexConverter low_converter (.din(tx_data[3:0]), .dout(low_char));
	
	reg[7:0] low_char_buf = 0;
	
	reg txing_high = 0;
	always @(posedge clk) begin
	
		uart_txdata <= 0;
		uart_txen <= 0;
	
		//Process existing stuff
		if(busy) begin
			
			//Skip if txen is active since the uart hasn't yet set the busy flag
			//If not, and UART isn't busy, we can send it another byte
			if(!uart_txen && !uart_tx_busy) begin
				
				//Transmit low char
				if(txing_high) begin
					txing_high <= 0;
					uart_txdata <= low_char_buf;
					uart_txen <= 1;
				end
				
				//We're done
				else begin
					busy <= 0;
				end
				
			end
			
		end
	
		//New commands
		else begin
			
			//Transmit a new hex character
			if(tx_en) begin
				txing_high <= 1;
				low_char_buf <= low_char;
				busy <= 1;
				uart_txdata <= high_char;
				uart_txen <= 1;
			end
			
			//Transmit a line break
			if(newline_en) begin
				txing_high <= 1;
				low_char_buf <= 8'h0a;		//\n
				busy <= 1;
				uart_txdata <= 8'h0d;		//\r
				uart_txen <= 1;
			end
			
			//Transmit a single space
			if(space_en) begin
				txing_high <= 0;
				busy <= 1;
				uart_txdata <= " ";
				uart_txen <= 1;
			end
			
		end
		
	end

endmodule

module HexConverter(din, dout);

	input wire[3:0] din;
	output reg[7:0] dout = 0;
	
	always @(din) begin
		case(din)
			4'h0:		dout <= "0";
			4'h1:		dout <= "1";
			4'h2:		dout <= "2";
			4'h3:		dout <= "3";
			4'h4:		dout <= "4";
			4'h5:		dout <= "5";
			4'h6:		dout <= "6";
			4'h7:		dout <= "7";
			4'h8:		dout <= "8";
			4'h9:		dout <= "9";
			4'ha:		dout <= "a";
			4'hb:		dout <= "b";
			4'hc:		dout <= "c";
			4'hd:		dout <= "d";
			4'he:		dout <= "e";
			4'hf:		dout <= "f";
		endcase
	end

endmodule
